#include "MvMedia.h"
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "work_object.h"
#include "common/sample_common.h"
#include "rkmedia_api.h"
#include "rga/im2d.h"
#include "rga/rga.h"

#ifdef ENABLE_VENC_AND_SHM
#include "rkmedia_venc.h"
#include "utils/avpacketq/avpacketq.h"

#define AVPAKCET_BUFFER_SIZE (1024 * 1024)
static inline uint64_t get_timestamp_ms() {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}
#endif

class MVMedia::MVMediaImpl {
public:
    MVMediaImpl();
    ~MVMediaImpl();
    int init(const uint32_t InWidth, const uint32_t InHeight, const uint32_t OutWidth, const uint32_t OutHeight, const uint32_t rotation);
    int deInit();
    int startReg();
    int stopReg();
    void registerDataSyncFunc(const std::function<int(uint8_t*)> &cb);
    void release();
private:
    MPP_CHN_S stSrcChn;
    MPP_CHN_S stDestChn;
    RK_S32 s32CamId;
    VI_CHN_ATTR_S vi_chn_attr;
    std::atomic_bool isInited;
    std::atomic_bool isExit;
    std::atomic_bool isStarted;
    struct _thread_object algoObject;
#ifdef ENABLE_VENC_AND_SHM
    struct _thread_object liveObject;
    avpacketq_t* m_live;
#endif
    std::function<int(uint8_t*)> mCb;
private:
    void GetMediaBuffer();
#ifdef ENABLE_VENC_AND_SHM
    void VENCToLive();
#endif
};

MVMedia::MVMediaImpl::MVMediaImpl() {
    isInited.store(false);
}

MVMedia::MVMediaImpl::~MVMediaImpl() {

}

int MVMedia::MVMediaImpl::init(const uint32_t InWidth, const uint32_t InHeight, const uint32_t OutWidth, const uint32_t OutHeight, const uint32_t rotation) {
    if(isInited.load()) return -1;
    isExit.store(false);
    isStarted.store(false);
#ifdef ENABLE_VENC_AND_SHM
    m_live = avpacketq_new("camera", 3, AVPAKCET_BUFFER_SIZE);
    if(nullptr == m_live) return -1;
    encoder_info_t encoder_info;
    encoder_info.encoder_param.type = 0;  // 视频编码方式, H264: 0; H265:1
    encoder_info.encoder_param.width = static_cast<int>(OutWidth);
    encoder_info.encoder_param.height = static_cast<int>(OutHeight);
    encoder_info.encoder_param.frame_rate = 25;
    encoder_info.encoder_param.bitrate = 4000000;
    avpacketq_set_encoder_info(m_live, &encoder_info);
#endif
    RK_S32 ret;
    // IMAGE_TYPE_E enPixFmt = IMAGE_TYPE_FBC0;
    IMAGE_TYPE_E enPixFmt = IMAGE_TYPE_NV12;
    const RK_CHAR *pcVideoNode = "rkispp_m_bypass";
    s32CamId = 1;
#ifdef RKAIQ
    RK_BOOL bMultictx = RK_FALSE;
#endif
#ifdef RKAIQ
    rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;//RK_AIQ_WORKING_MODE_NORMAL;
    int fps = 30;
    SAMPLE_COMM_ISP_Init(s32CamId, hdr_mode, bMultictx, "/etc/iqfiles");
    SAMPLE_COMM_ISP_Run(s32CamId);
    SAMPLE_COMM_ISP_SetFrameRate(s32CamId, fps);
#endif
    ret = RK_MPI_SYS_Init();  //初始化Rockchip媒体系统
    if (ret) {
        fprintf(stderr, "Sys Init failed! ret=%d\n", ret);
#ifdef RKAIQ
        SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
#ifdef ENABLE_VENC_AND_SHM
        avpacketq_destroy(&m_live, 0);
#endif
        return -1;
    }
    //配置摄像头采集通道属性并启用
    vi_chn_attr.pcVideoNode = pcVideoNode;
    vi_chn_attr.u32BufCnt = 3;
    vi_chn_attr.u32Width = InWidth;
    vi_chn_attr.u32Height = InHeight;
    vi_chn_attr.enPixFmt = enPixFmt;
    vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
    ret = RK_MPI_VI_SetChnAttr(s32CamId, s32CamId, &vi_chn_attr);
    ret |= RK_MPI_VI_EnableChn(s32CamId, s32CamId);
    if (ret) {
        fprintf(stderr, "Create Vi failed! ret=%d\n", ret);
#ifdef RKAIQ
        SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
#ifdef ENABLE_VENC_AND_SHM
        avpacketq_destroy(&m_live, 0);
#endif
        return -1;
    }
#if 0
    // Create H265 for Main Stream. 创建H265 编码通道
    VENC_CHN_ATTR_S venc_chn_attr;
    memset(&venc_chn_attr, 0, sizeof(venc_chn_attr));
    venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H265;
    venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_FBC0;
    venc_chn_attr.stVencAttr.u32PicWidth = width;
    venc_chn_attr.stVencAttr.u32PicHeight = height;
    venc_chn_attr.stVencAttr.u32VirWidth = width;
    venc_chn_attr.stVencAttr.u32VirHeight = height;
    venc_chn_attr.stVencAttr.u32Profile = 77;
    venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 30;
    venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate =
        width * height * 30 / 14;
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 0;
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 30;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 0;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 30;
    ret = RK_MPI_VENC_CreateChn(0, &venc_chn_attr);
    if (ret) {
        printf("Create Venc(H265) failed! ret=%d\n", ret);
        return -1;
    }
#endif
    RGA_ATTR_S stRgaAttr_01;
    memset(&stRgaAttr_01, 0, sizeof(stRgaAttr_01));
    stRgaAttr_01.bEnBufPool = RK_TRUE;
    stRgaAttr_01.u16BufPoolCnt = 3;
    stRgaAttr_01.u16Rotaion = rotation;
    stRgaAttr_01.stImgIn.u32X = 0;
    stRgaAttr_01.stImgIn.u32Y = 0;
    stRgaAttr_01.stImgIn.imgType = IMAGE_TYPE_NV12;
    stRgaAttr_01.stImgIn.u32Width = InWidth;
    stRgaAttr_01.stImgIn.u32Height = InHeight;
    stRgaAttr_01.stImgIn.u32HorStride = InWidth;
    stRgaAttr_01.stImgIn.u32VirStride = InHeight;
    stRgaAttr_01.stImgOut.u32X = 0;
    stRgaAttr_01.stImgOut.u32Y = 0;
    stRgaAttr_01.stImgOut.imgType = IMAGE_TYPE_NV12;
    stRgaAttr_01.stImgOut.u32Width = OutWidth;
    stRgaAttr_01.stImgOut.u32Height = OutHeight;
    stRgaAttr_01.stImgOut.u32HorStride = OutWidth;
    stRgaAttr_01.stImgOut.u32VirStride = OutHeight;
    ret = RK_MPI_RGA_CreateChn(s32CamId, &stRgaAttr_01);
    if (ret)
    {
        fprintf(stderr, "ERROR: create RGA[0:0] falied! ret=%d\n", ret);
        RK_MPI_VI_DisableChn(s32CamId, s32CamId);
#ifdef RKAIQ
        SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
#ifdef ENABLE_VENC_AND_SHM
        avpacketq_destroy(&m_live, 0);
#endif
        return -1;
    }
#ifdef ENABLE_VENC_AND_SHM
    stRgaAttr_01.stImgOut.imgType = IMAGE_TYPE_RGB888;
    ret = RK_MPI_RGA_CreateChn(s32CamId + 5, &stRgaAttr_01);

    VENC_ROTATION_E en_rotation;
    switch (rotation) {
        case 0:en_rotation = VENC_ROTATION_0;break;
        case 90:en_rotation = VENC_ROTATION_90;break;
        case 180:en_rotation = VENC_ROTATION_180;break;
        case 270:en_rotation = VENC_ROTATION_270;break;
        default: {
            RK_MPI_RGA_DestroyChn(s32CamId + 5);
            RK_MPI_RGA_DestroyChn(s32CamId);
            RK_MPI_VI_DisableChn(s32CamId, s32CamId);
#ifdef RKAIQ
            SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
#ifdef ENABLE_VENC_AND_SHM
            avpacketq_destroy(&m_live, 0);
#endif
            fprintf(stderr, "en_rotation falied! \n");
            return -1;
        }
    }

    VENC_CHN_ATTR_S venc_chn_attr;
    venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//IMAGE_TYPE_NV12;
    venc_chn_attr.stVencAttr.u32PicWidth = OutWidth;
    venc_chn_attr.stVencAttr.u32PicHeight = OutHeight;
    venc_chn_attr.stVencAttr.u32VirWidth = OutWidth;
    venc_chn_attr.stVencAttr.u32VirHeight = OutHeight;
    venc_chn_attr.stVencAttr.enRotation = VENC_ROTATION_0;
    venc_chn_attr.stVencAttr.u32Profile = 77;
    venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;
    venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 30;
    venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = 4000000;  //2000000; // 2Mb
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;
    ret = RK_MPI_VENC_CreateChn(s32CamId, &venc_chn_attr);
    if (ret) {
        fprintf(stderr, "Create venc[1] error! code:%d\n", ret);
        RK_MPI_RGA_DestroyChn(s32CamId + 5);
        RK_MPI_RGA_DestroyChn(s32CamId);
        RK_MPI_VI_DisableChn(s32CamId, s32CamId);
#ifdef RKAIQ
        SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
#ifdef ENABLE_VENC_AND_SHM
        avpacketq_destroy(&m_live, 0);
#endif
        return -1;
    }
#endif
    fprintf(stderr, "Bind VI[0:0] to RGA[0:0]....\n");
    stSrcChn.enModId = RK_ID_VI;
    // stSrcChn.s32DevId = s32CamId;
    stSrcChn.s32ChnId = s32CamId;
    stDestChn.enModId = RK_ID_RGA;
    // stSrcChn.s32DevId = s32CamId;
    stDestChn.s32ChnId = s32CamId;
    ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if (ret)
    {
        fprintf(stderr, "ERROR: bind VI[0:0] to RGA[0:0] failed! ret=%d\n", ret);
#ifdef ENABLE_VENC_AND_SHM
        RK_MPI_VENC_DestroyChn(s32CamId);
        RK_MPI_RGA_DestroyChn(s32CamId + 5);
        avpacketq_destroy(&m_live, 0);
#endif
        RK_MPI_RGA_DestroyChn(s32CamId);
        RK_MPI_VI_DisableChn(s32CamId, s32CamId);
#ifdef RKAIQ
        SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
        return -1;
    }
#ifdef ENABLE_VENC_AND_SHM
    stDestChn.s32ChnId = s32CamId + 5;
    ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if (ret) {
        fprintf(stderr, "Bind vi[%d] and rga[%d] failed! ret=%d\n", s32CamId, s32CamId + 5, ret);
#ifdef ENABLE_VENC_AND_SHM
        stDestChn.s32ChnId = s32CamId;
        RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
        RK_MPI_VENC_DestroyChn(s32CamId);
        RK_MPI_RGA_DestroyChn(s32CamId + 5);
        avpacketq_destroy(&m_live, 0);
#endif
        RK_MPI_RGA_DestroyChn(s32CamId);
        RK_MPI_VI_DisableChn(s32CamId, s32CamId);
#ifdef RKAIQ
        SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
        return -1;
    }
    stSrcChn.enModId = RK_ID_RGA;
    stSrcChn.s32ChnId = s32CamId;
    stDestChn.enModId = RK_ID_VENC;
    stDestChn.s32ChnId = s32CamId;
    ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if (ret) {
        fprintf(stderr, "Bind rga[%d] to venc[%d] error! code:%d\n", s32CamId, s32CamId, ret);
        stSrcChn.enModId = RK_ID_VI;
        stSrcChn.s32ChnId = s32CamId;
        stDestChn.enModId = RK_ID_RGA;
        stDestChn.s32ChnId = s32CamId + 5;
        RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
        stSrcChn.enModId = RK_ID_VI;
        stSrcChn.s32ChnId = s32CamId;
        stDestChn.enModId = RK_ID_RGA;
        stDestChn.s32ChnId = s32CamId;
        RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
#ifdef ENABLE_VENC_AND_SHM
        RK_MPI_VENC_DestroyChn(s32CamId);
        RK_MPI_RGA_DestroyChn(s32CamId + 5);
        avpacketq_destroy(&m_live, 0);
#endif
        RK_MPI_RGA_DestroyChn(s32CamId);
        RK_MPI_VI_DisableChn(s32CamId, s32CamId);
#ifdef RKAIQ
        SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
        return -1;
    }
#endif
    // ret = RK_MPI_VI_StartStream(s32CamId, 1);
    algoObject.work_thread = std::move(std::thread(&MVMedia::MVMediaImpl::GetMediaBuffer, this));
#ifdef ENABLE_VENC_AND_SHM
    liveObject.work_thread = std::move(std::thread(&MVMedia::MVMediaImpl::VENCToLive, this));
#endif
#if 0
    stSrcChn.enModId = RK_ID_VI;
    stSrcChn.s32ChnId = 0;
    stDestChn.enModId = RK_ID_VENC;
    stDestChn.s32ChnId = 0;
    ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if (ret) {
        fprintf(stderr, "Bind VI[0] to VENC[0]::H265 failed! ret=%d\n", ret);
        deInit();
        return -1;
    }
#endif
#if 0
    stDestChn.s32ChnId = 1;
    ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn); //绑定摄像头采集通道和编码器输入通道
    if (ret) {
        fprintf(stderr, "Bind VI[0] to VENC[1]::JPEG failed! ret=%d\n", ret);
        return -1;
    }
#endif
    fprintf(stderr, "MVMedia initial finish\n");
    isInited.store(true);
    return 0;
}

int MVMedia::MVMediaImpl::deInit() {
    if(!isInited.load()) return 0;
    stopReg();
    isExit.store(true);
    if(algoObject.work_thread.joinable()) {
        algoObject.work_cond.notify_one();
        algoObject.work_thread.join();
    }
#ifdef ENABLE_VENC_AND_SHM
    if(liveObject.work_thread.joinable()) {
        liveObject.work_thread.join();
    }
#endif
    fprintf(stderr, "UnBind VI[0:0] to RGA[0:0]....\n");
    stSrcChn.enModId = RK_ID_VI;
    stSrcChn.s32ChnId = s32CamId;
    stDestChn.enModId = RK_ID_RGA;
    stDestChn.s32ChnId = s32CamId + 5;
    RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
#ifdef ENABLE_VENC_AND_SHM
    avpacketq_destroy(&m_live, 0);
    stSrcChn.enModId = RK_ID_VI;
    stSrcChn.s32ChnId = s32CamId;
    stDestChn.enModId = RK_ID_RGA;
    stDestChn.s32ChnId = s32CamId;
    RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
    stSrcChn.enModId = RK_ID_RGA;
    stSrcChn.s32ChnId = s32CamId;
    stDestChn.enModId = RK_ID_VENC;
    stDestChn.s32ChnId = s32CamId;
    RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
    RK_MPI_VENC_DestroyChn(s32CamId);
    RK_MPI_RGA_DestroyChn(s32CamId);
#endif

    RK_MPI_RGA_DestroyChn(s32CamId + 5);
    RK_MPI_VI_DisableChn(s32CamId, s32CamId);

#ifdef RKAIQ
    SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
    isInited.store(false);
    return 0;
}

int MVMedia::MVMediaImpl::startReg() {
    if(!isInited.load()) return -1;
    isStarted.store(true);
    algoObject.work_cond.notify_one();
    return 0;
}

int MVMedia::MVMediaImpl::stopReg() {
    if(!isInited.load()) return -1;
    isStarted.store(false);
    return 0;
}

void MVMedia::MVMediaImpl::registerDataSyncFunc(const std::function<int(uint8_t*)> &cb) {
    if(!isInited.load()) return;
    mCb = cb;
}

void MVMedia::MVMediaImpl::GetMediaBuffer() {
    MEDIA_BUFFER mb = NULL;

    while (!isExit.load()) {
        std::unique_lock<std::mutex> lk(algoObject.work_lock);
        algoObject.work_cond.wait(lk, [this](){return isExit.load() || isStarted.load();});
        if(isExit.load()) break;
        while(isStarted.load()) {
            static int index = 0;

            mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, s32CamId + 5, -1);

            if (!mb) {
                fprintf(stderr, "RK_MPI_SYS_GetMediaBuffer get null buffer!\n");
                break;
            }
            if(index < 10) {
                index++;
                RK_MPI_MB_ReleaseBuffer(mb);
                continue;
            }
#if 0
            FILE* fp = NULL;
            fp = fopen("/root/testMat.bgr", "r");
            if(NULL != fp) {
                fclose(fp);
            }else {
                fp = fopen("/root/testMat.bgr", "w");
                fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, fp);
            }
#endif
            if(mCb.operator bool()) {
                mCb((uint8_t*)RK_MPI_MB_GetPtr(mb));
            }
            RK_MPI_MB_ReleaseBuffer(mb);
        }
        usleep(50000);
    }
    fprintf(stderr, "%s func finish\n", __func__);
}

#ifdef ENABLE_VENC_AND_SHM
#define H264_NAL(v) (v & 0x1F)
enum { NAL_IDR = 5, NAL_SEI = 6, NAL_SPS = 7, NAL_PPS = 8 };

static const uint8_t* h264_startcode(const uint8_t* data, size_t bytes) {
    size_t i;
    for (i = 2; i + 1 < bytes; i++) {
        if (0x01 == data[i] && 0x00 == data[i - 1] && 0x00 == data[i - 2])
            return data + i + 1;
    }
    return NULL;
}

static inline int h264_nal_type(const unsigned char* ptr) {
    int i = 2;
    assert(0x00 == ptr[0] && 0x00 == ptr[1]);
    if (0x00 == ptr[2])
        ++i;
    assert(0x01 == ptr[i]);
    return H264_NAL(ptr[i + 1]);
}

void MVMedia::MVMediaImpl::VENCToLive() {
    unsigned int sn = 0;
    bool sps_write = false;
    while (!isExit.load()) {
        MEDIA_BUFFER mb = nullptr;
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, s32CamId, -1);
        if (!mb) {
            fprintf(stderr, "RK_MPI_SYS_GetMediaBuffer get null buffer!");
            return;
        }

        uint8_t* mb_ptr = (uint8_t*) RK_MPI_MB_GetPtr(mb);
        size_t bytes = RK_MPI_MB_GetSize(mb);

        const uint8_t* end = mb_ptr + bytes;
        
        const uint8_t* p_nalu = h264_startcode(mb_ptr, RK_MPI_MB_GetSize(mb));
        uint8_t nalutype = p_nalu[0] & 0x1f;
        size_t nalu_len = 0;
        if (!sps_write && (nalutype == 7)) {
            char* sps = nullptr;
            int sps_len = 0;
            sps = (char*) malloc(512);

            size_t start_code_len = p_nalu - mb_ptr;

            // printf("start_code_len: %ld, size: %ld\n", start_code_len, RK_MPI_MB_GetSize(mb));

            memcpy(sps, p_nalu, 20);
            sps_len = 20;
            uint8_t* ptr = (uint8_t*) sps;
            for (int i = 0;i < sps_len;i++)
                fprintf(stderr, "0x%02x ", *ptr++);
            fprintf(stderr, "\n");

            encoder_info_t encoder_info;
            encoder_info.encoder_extra.data = (uint8_t*) sps;
            encoder_info.encoder_extra.len = sps_len;
            avpacketq_set_encoder_info(m_live, &encoder_info);
            sps_write = true;
            if (!sps) {
                free(sps);
            }
        }

        if (!sps_write) {
            RK_MPI_MB_ReleaseBuffer(mb);
            continue;
        }

        #if 0
            FILE* fp = NULL;
            fp = fopen("/root/testMat.h264", "a+");
            fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, fp);
        #endif

        avpacket_info_t avpacket_info;

        if (RK_MPI_MB_GetFlag(mb) == VENC_NALU_IDRSLICE) {
            // printf("%d find iframe!!!\n", m_s32CamId);
            avpacket_info.iframe = 1;
        }
        else {
            avpacket_info.iframe = 0;
        }
        avpacket_info.data = RK_MPI_MB_GetPtr(mb);
        avpacket_info.data_len = RK_MPI_MB_GetSize(mb);
        avpacket_info.ts = get_timestamp_ms();

        if (sn > 0xffffffff) {
            sn = 0;
        }
        avpacket_info.sn = sn;
        sn++;

        int ret;
        ret = avpacketq_enqueue(m_live, &avpacket_info);

        static int print_interval = 0;
        print_interval++;
        if (print_interval == 1 || print_interval % 500 == 1) {
            fprintf(stderr, "avpacket_info.sn: %llu avpacket_info.data_len: %d\n", avpacket_info.sn, avpacket_info.data_len);
        }

        RK_MPI_MB_ReleaseBuffer(mb);
    }
    fprintf(stderr, "%s func finish\n", __func__);
}
#endif

void MVMedia::MVMediaImpl::release() {
    deInit();
}

MVMedia::MVMedia():pImpl(std::make_unique<MVMediaImpl>()) {

}

MVMedia::~MVMedia() {
}

int MVMedia::init(const uint32_t InWidth, const uint32_t InHeight, const uint32_t OutWidth, const uint32_t OutHeight, const uint32_t rotation) {
    return pImpl->init(InWidth, InHeight, OutWidth, OutHeight, rotation);
}

int MVMedia::deInit() {
    return pImpl->deInit();
}

int MVMedia::startReg() {
    return pImpl->startReg();
}

int MVMedia::stopReg() {
    return pImpl->stopReg();
}

void MVMedia::registerDataSyncFunc(const std::function<int(uint8_t*)> &cb) {
    pImpl->registerDataSyncFunc(cb);
}

void MVMedia::release() {
    pImpl->release();
}